#include "compresseddata.h"
#include "log.h"
#include <fstream>

using namespace std;

CompressedData::CompressedData(string &path) :
		path(path)
{
}

CompressedData::CompressedData(std::string& path, int M, int wordSize,
		std::vector<int> &dictionary, int lastSize) :
		path(path), M(M), wordSize(wordSize), dictionary(dictionary), lastSize(
				lastSize)
{
}

CompressedDataInput::CompressedDataInput(std::string& path) :
		CompressedData(path)
{
	logger.info("Reading file '" + path + "'...", true);
	fstream file(path.c_str(), ios_base::in | ios_base::binary);
	data = BitStream(file);
	file.close();

	M = data.get(8);
	wordSize = data.get(8);
	lastSize = data.get(5);
	data.remainder = data.get(3);

	int length = data.get(wordSize) + 1;
	for (int i = 0; i < length; i++)
	{
		dictionary.push_back(data.get(wordSize));
		logger.progress(i + 1, length);
	}
}

int CompressedDataInput::get()
{
	return data.get();
}

CompressedDataOutput::CompressedDataOutput(std::string& path, int M,
		int wordSize, std::vector<int> &dictionary, int lastSize) :
		CompressedData(path, M, wordSize, dictionary, lastSize)
{
	data.put(M, 8);
	data.put(wordSize, 8);
	data.put(0, 8);
	data.put(dictionary.size() - 1, wordSize);
	for (unsigned int i = 0; i < dictionary.size(); i++)
		data.put(dictionary[i], wordSize);
}

void CompressedDataOutput::put(int bit)
{
	data.put(bit);
}

void CompressedDataOutput::commit()
{
	logger.info("Writing file '" + path + "'...", true);
	ostream* file;
	if (path.empty())
		file = &cout;
	else
		file = new fstream(path.c_str(), ios_base::out | ios_base::binary);

	data[2] = (lastSize << 3) | (data.remainder & 7);
	for (int i = 0; i < data.length(); i++)
	{
		file->put(data[i]);
		logger.progress(i + 1, data.length());
	}
	if (!path.empty())
	{
		((fstream*) file)->close();
		delete file;
	}
}
